home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2000 / MacHack 2000.toast / pc / The Hacks / EtherPEG / (sources) / SortFrames.cp < prev    next >
Encoding:
Text File  |  2000-06-24  |  7.0 KB  |  248 lines

  1. #include "SortFrames.h"
  2.  
  3. #include <Errors.h>
  4. #include <MacMemory.h>
  5.  
  6. enum { kFree, kCaptured, kDisplaying};
  7. typedef struct StashedPacket StashedPacket;
  8. struct StashedPacket
  9.     {
  10.     SInt32 state;                // Free, captured packet, or data being displayed
  11.     Packet *data;
  12.     SInt32 payloadoffset;
  13.     SInt32 SOI;
  14.     SInt32 EOI;
  15.     StashedPacket *parent;
  16.     StashedPacket *next;
  17.     StashedPacket *following;
  18.     };
  19.  
  20. enum {
  21.     kMaxPacketLength = 1500
  22. };
  23. enum {
  24.     kStashSize = 1000
  25. };
  26.  
  27. StashedPacket stash[kStashSize];
  28. UInt32 nextStashEntry = 0;
  29.  
  30. OSErr createStash(void)
  31. {
  32.     for (int i = 0; i < kStashSize; i++)
  33.     {
  34.         stash[i].state = kFree;
  35.         stash[i].data = (Packet*)NewPtr(kMaxPacketLength);
  36.         if (!stash[i].data) { DebugStr("\p out of memory, createStash"); return(memFullErr); }
  37.     }
  38.     return noErr;
  39. }
  40.  
  41. void destroyStash(void)
  42. {
  43.     SInt16 probe;
  44.     for( probe = 0; probe < kStashSize; probe++ ) {
  45.         DisposePtr((Ptr)stash[probe].data);
  46.         stash[probe].data = nil;
  47.     }
  48. }
  49.  
  50. static void RecyclePacketChain(StashedPacket *parent)
  51. {
  52.     // Recycle the chain of packets chained off this parent packet
  53.     for (StashedPacket *p=parent; p; p=p->next) p->state = kFree;
  54. }
  55.  
  56. static void TrimPacketChain(StashedPacket *p)
  57. {
  58.     if (!p) return;
  59.     
  60.     // Free up to the next packet with a start marker
  61.     do { p->state = kFree; p=p->next; } while (p && (p->SOI == -1));
  62.     
  63.     if (p)    // If we have packet with a start marker
  64.     {
  65.         for (StashedPacket *q = p; q; q=q->next) q->parent = p;
  66.         p->parent = NULL;
  67.     }
  68. }
  69.  
  70. static void harvestJPEG(StashedPacket *parent)
  71. {
  72.     if (parent->SOI == -1) { DebugStr("\pERROR! parent packet has no SOI"); return; }
  73.     
  74.     SInt32 totalSize = parent->payloadoffset - parent->SOI;
  75.     if (parent->EOI != -1 && parent->EOI < parent->SOI) parent->EOI = -1;
  76.     
  77.     StashedPacket *p = parent;
  78.     while (p->EOI == -1)        // While we've not found the end, look for more in-order packets
  79.     {
  80.         totalSize += p->data->totalLength - p->payloadoffset;
  81.         SInt32 targetseqnum = p->data->sequenceNumber + p->data->totalLength - p->payloadoffset;
  82.         StashedPacket *srch;
  83.         for (srch = parent; srch; srch=srch->next)
  84.             if (srch->data->sequenceNumber == targetseqnum)        // We found the right packet
  85.             {
  86.                 p->following = srch;                            // Link it in
  87.                 p = srch;                                        // Move p one packet forward
  88.                 break;                                            // and continue
  89.             }
  90.         // If we couldn't find the desired sequence number, leave the chain in place
  91.         // -- it might get completed later
  92.         if (!srch) return;
  93.     }
  94.  
  95.     totalSize += p->EOI - p->payloadoffset;
  96.     Handle h = NewHandle( totalSize );
  97.     
  98.     if( h ) {
  99.         Ptr ptr = *h;
  100.         
  101.         SInt32 size = parent->data->totalLength - parent->SOI;
  102.         if (parent->following == NULL) size += parent->EOI - parent->data->totalLength;
  103.         BlockMoveData( ((Ptr)(parent->data)) + parent->SOI, ptr, size );
  104.         ptr += size;
  105.         
  106.         p = parent->following;
  107.         while (p)
  108.             {
  109.             size = p->data->totalLength - p->payloadoffset;
  110.             if (p->following == NULL) size += p->EOI - p->data->totalLength;
  111.             BlockMoveData( ((Ptr)(p->data)) + p->payloadoffset, ptr, size );
  112.             ptr += size;
  113.             p = p->following;
  114.             }
  115.  
  116.         DisplayJPEGAndDisposeHandle(h);
  117.     }
  118.     //else DebugStr("\p out of memory, harvestJPEG");
  119.  
  120.     TrimPacketChain(parent);
  121. }
  122.  
  123. static SInt32 getOffsetToPayload( Packet *packet )
  124. {
  125.     #define kIPHeaderLength    20
  126.     short tcpHeaderLength = (packet->dataOffsetAndJunk >> 2) & ~3;
  127.     return kIPHeaderLength + tcpHeaderLength;
  128. }
  129.  
  130. static void ensureFreeSlotInStash()
  131. {
  132.     StashedPacket *p = &stash[nextStashEntry];
  133.     
  134.     if (p->state != kFree)
  135.     {
  136.         if (p->SOI != -1) harvestJPEG(p);
  137.         while (p->state != kFree)        // If harvestJPEG was unable to pull a good image
  138.         {                                // out of the chain, then trash it anyway to make space
  139.              TrimPacketChain(p->parent ? p->parent : p);
  140.          }
  141.     }
  142. }
  143.  
  144. static StashedPacket *addPacketToStash(Packet *packetdata, SInt32 SOI, SInt32 EOI, StashedPacket *parent)
  145. {
  146.     if (!parent && SOI == -1) { DebugStr("\paddPacketToStash invalid packet"); return(NULL); }
  147.     if (packetdata->totalLength > kMaxPacketLength) return(NULL);
  148.     
  149.     StashedPacket *p = &stash[nextStashEntry];
  150.     if (p->state != kFree) { DebugStr("\paddPacketToStash no free space"); return(NULL); }
  151.     if (++nextStashEntry >= kStashSize) nextStashEntry = 0;
  152.  
  153.     p->state  = kCaptured;
  154.     BlockMoveData(packetdata, p->data, packetdata->totalLength);
  155.     p->payloadoffset = getOffsetToPayload(p->data);
  156.     p->SOI    = SOI;
  157.     p->EOI    = EOI;
  158.     p->parent = parent;
  159.     p->next   = NULL;
  160.     p->following = NULL;
  161.     
  162.     if (parent)
  163.         {
  164.         p->next = parent->next;
  165.         parent->next = p;
  166.         }
  167.     
  168.     return(p);
  169. }
  170.  
  171. static StashedPacket *findParentPacket(Packet *packet)
  172.     {
  173.     for (int i = 0; i < kStashSize; i++)        // Search for matching packet
  174.         {
  175.         Packet *p = stash[i].data;
  176.         if (stash[i].state == kCaptured &&
  177.             p->sourceIP   == packet->sourceIP   && p->destIP   == packet->destIP &&
  178.             p->sourcePort == packet->sourcePort && p->destPort == packet->destPort)
  179.             {
  180.             // If this packet already has a parent, we share the same parent
  181.             if (stash[i].parent) return (stash[i].parent);
  182.             else return(&stash[i]);        // Else this packet is our parent
  183.             }
  184.         }
  185.     return (NULL);
  186.     }
  187.  
  188. static void searchForImageMarkers(Packet *packet, SInt32 *offsetOfSOI, SInt32 *offsetAfterEOI)
  189. {
  190.     
  191.     UInt8 *packetStart, *dataStart, *dataEnd, *data;
  192.     packetStart = (UInt8 *) packet;
  193.     dataStart = packetStart + getOffsetToPayload(packet);    // first byte that might contain actual payload
  194.     dataEnd = packetStart + packet->totalLength;    // byte after last byte that might contain actual payload
  195.     
  196.     *offsetOfSOI = -1;
  197.     *offsetAfterEOI = -1;
  198.     
  199.     for( data = dataStart; data <= dataEnd-3; data++ ) {
  200.         // JPEG SOI is FF D8, but it's always followed by another FF.
  201.         if( ( 0xff == data[0] ) && ( 0xd8 == data[1] ) && ( 0xff == data[2] ) )
  202.             *offsetOfSOI = data - packetStart;
  203.         
  204.         // GIF start marker is 'GIF89a' etc.
  205.         if ('G' == data[0] && 'I' == data[1] && 'F' == data[2] && '8' == data[3])
  206.             *offsetOfSOI = data - packetStart;
  207.     }
  208.     for( data = dataStart; data <= dataEnd-2; data++ ) {
  209.         // JPEG EOI is always FF D9.
  210.         if( ( 0xff == data[0] ) && ( 0xd9 == data[1] ) )
  211.             *offsetAfterEOI = data - packetStart + 2; // caller will need to grab 2 extra bytes.
  212.     }
  213.     
  214.     if (packet->moreFlagsAndJunk & kFINBit)
  215.         *offsetAfterEOI = packet->totalLength;
  216. }
  217.  
  218. void ConsumePacket( Packet *packet )
  219. {
  220.     SInt32 SOI, EOI;
  221.     
  222.     if( packet->protocol != 6 ) goto toss; // only TCP packets please
  223.     if( ( packet->versionAndIHL & 0x0f ) != 5 ) goto toss; // minimal IP headers only (lame?)
  224.     
  225.     ensureFreeSlotInStash();
  226.     
  227.     StashedPacket *p = NULL;
  228.     StashedPacket *parent = findParentPacket(packet);
  229.     searchForImageMarkers(packet, &SOI, &EOI);
  230.  
  231.     Boolean addMe = false, harvestMe = false;
  232.     
  233.     // If this packet contains an image start marker, or continues an existing sequence, then stash it
  234.     if (parent || SOI != -1) addMe = true;
  235.     if (addMe) p = addPacketToStash(packet, SOI, EOI, parent);
  236.     
  237.     // If this packet contains an image end marker, and we successfully stashed it, then harvest the packet
  238.     if (p && EOI != -1) harvestMe = true;
  239.     if (harvestMe) harvestJPEG(parent ? parent : p);
  240.  
  241.     if      (harvestMe) showBlob(3); // blue
  242.     else if (addMe)     showBlob(2); // green
  243.     else                showBlob(1); // black
  244.     return;
  245. toss:
  246.     showBlob( 0 ); // yellow
  247. }
  248.